package structures.stack;

public class CalculatorDemo {
    public static void main(String[] args) {
        String expression = "3+2110*6-202";
        // 创建两个栈，一个保存数字，一个保存运算符
        CalculatorStack numStack = new CalculatorStack(10);
        CalculatorStack operStack = new CalculatorStack(10);
        // 定义需要的变量
        int res = 0;

        for (int index = 0; index < expression.length(); index++) {
            char charAt = expression.charAt(index);

            // 是数字
            if (CalculatorStack.priority(charAt) < 0) {
                // 存储数字
                StringBuilder num = new StringBuilder(String.valueOf(charAt - 48));
                // 循环判断
                while ((expression.length() - 1) > index &&
                        CalculatorStack.priority(expression.charAt(++index)) < 0) {
                    num.append(String.valueOf(expression.charAt(index) - 48));
                }
                // 去掉while里面判断失败 ++index
                if (expression.length() > index + 1) {
                    index--;
                }
                numStack.push(Integer.parseInt(String.valueOf(num)));     // char 转具体数字
                continue;
            }

            System.out.println("---符号--" + charAt);
            // 是符号
            // 如果栈中没有操作符 则直接入栈
            if (operStack.isEmpty()) {
                operStack.push(charAt);
                continue;
            }

            // 有操作符  取出操作符进行优先级比较  当前优先级比较高 则存入栈中
            if (CalculatorStack.priority(charAt) >
                    CalculatorStack.priority(operStack.peekTop())) {
                operStack.push(charAt);
                continue;
            }
            // 有操作符  优先级小于、等于从栈中取出的优先级  则取出2个数据、取出一个操作符进行比较,并把charAt入栈
            int popOper = operStack.pop();
            res = CalculatorStack.cal(numStack.pop(),
                    numStack.pop(),
                    popOper);
            // 把运算结果入栈
            numStack.push(res);
            // 把操作符入栈
            operStack.push(charAt);
        }

        // 取出剩余操作符顺序计算
        while (!operStack.isEmpty()) {
            res = CalculatorStack.cal(numStack.pop(),
                    numStack.pop(),
                    operStack.pop());
            numStack.push(res);
        }
        System.out.println("------最终计算结果: " + numStack.pop() + " ---------");
    }
}




class CalculatorStack {
    private final int maxSize;
    private int index = -1;
    private final int[] array;

    public CalculatorStack(int maxSize) {
        this.maxSize = maxSize;
        array = new int[maxSize];
    }

    /**
     * 判断是否为空
     * @return boolean
     */
    public boolean isEmpty() {
        return index < 0;
    }

    /**
     * 判断是否满
     * @return boolean
     */
    public boolean isFull() {
        return index >= (maxSize - 1);
    }

    /**
     * 添加
     * @param data
     * @return boolean
     */
    public boolean push(int data) {
        if (!isFull()) {
            array[++index] = data;
            return true;
        }
        System.out.println("添加数据失败,已满");
        return false;
    }

    /**
     * 取出
     * @return data
     */
    public int pop() {
        if (!isEmpty()) {
            return array[index--];
        }
        throw new RuntimeException("栈为空");
    }

    /**
     * 获取栈顶值, 不取出
     * @return
     */
    public int peekTop() {
        if (!isEmpty()) {
            return array[index];
        }
        throw new RuntimeException("栈为空..peek失败");
    }

    /**
     * 遍历打印
     */
    public void list() {
        while (!isEmpty()) {
            System.out.print(pop() + "\t");
        }
        System.out.println();
    }


    /**
     * 返回运算符优先级,优先级是程序来确认的，优先级使用数字表示
     * 数字越大 则优先级越高
     * @param oper
     * @return 如果是运算符则 > -1
     */
    public static int priority(int oper) {
        switch (oper) {
            case '*':
            case '/':
                return 1;
            case '+':
            case '-':
                return 0;
            default:
                return -1;
        }
    }

    /**
     * 计算
     * @param num1  为后面的数据
     * @param num2  为前面的数据
     * @param oper  运算符
     * @return  返回值
     */
    public static int cal(int num1, int num2, int oper) {
        int res = 0;
        switch (oper) {
            case '+':
                res =  num2 + num1;
                break;
            case '-':
                res =  num2 - num1;
                break;
            case '*':
                res =  num2 * num1;
                break;
            case '/':
                res =  num2 / num1;
                break;
        }
        return res;
    }
}